#include "subwidget2.h"
#include "ui_subwidget2.h"

SubWidget2::SubWidget2(QSqlDatabase &db, int col, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::SubWidget2),
    m_db(db),
    m_col(col)
{
    ui->setupUi(this);

    setWindowTitle("数据库");

    //创建表
    this->m_row = 100;   //在这里定义行数和列数
    //this->m_col = 12;     //成员初始化列中帮其定义了
    this->tableInit(this->m_row);    //初始化表格row=30、col=13
    //表格标签属性初始化，plot和plot_all_chart函数用
    m_lineNames <<"炉温"<< "风温1"<< "风温2"<<"风温3"<< "塔温1"<< "塔温2"<< "塔温3"<< "炉排"<<"排粮量"<< "干粮水分"<< "湿粮水分";
    //数据库设置初始查询内容
    this->moveDataBase_to_table();
    //初始化两个时间编辑按钮
    dateTimeButtonInit();

    //槽函数
    //connect(ui->pushButton, &QPushButton::clicked, this, [=](){this->query_by_datatime(); this->plot_all_chart();});
    connect(ui->pushButton, &QPushButton::clicked, this, [=](){QStringList temp_data = this->query_by_datatime(); emit(sql_by_dataTime(temp_data)); this->plot_all_chart();});      //通过这个按钮来触发信号，然后我们即可在MainWindow.cpp中感受到信号发出，从而调用

    connect(ui->pushButton_chart1_all, &QPushButton::clicked, this, [=](){this->plot_all_chart();});
    connect(ui->pushButton_chart1_V, &QPushButton::clicked,this
                ,[=](){
                    QVector<int> temp;
                    temp.push_back(e_t_wind1);
                    temp.push_back(e_t_wind2);
                    temp.push_back(e_t_wind3);
                    temp.push_back(e_t_tower1);
                    temp.push_back(e_t_tower2);
                    temp.push_back(e_t_tower3);
                    temp.push_back(e_t_furnace);
                    plot_chart(temp);
                }
            );
    connect(ui->pushButton_chart1_T, &QPushButton::clicked,this
                ,[=](){
                    QVector<int> temp;
                    temp.push_back(e_v_coal);
                    temp.push_back(e_v_grain);
                    plot_chart(temp);
                }
            );
}

/**
 * @brief SubWidget2::dateTimeButtonInit 为两个表设置默认时间
 */
void SubWidget2::dateTimeButtonInit()
{
    //设置时间
    //我们想要设置为一个固定的时间，这里setDateTime需要一个QDateTime类型参数，
    //两个思路：一个是找找有没有toDateTIme或者返回值为DateTime的函数(比如下面的fromString返回值为DateTime)
    //      另一个思路是构造一个DateTime类型的对象，看看其需要啥参数，这里发现需要QDate类型的参数，刚好后续QDate有fromString返回值为QDate的参数，所以采用这个方法
    ui->dateTimeEdit->setDateTime(QDateTime(QDate::fromString("26MM02car2020", "d'MM'MMcaryyyy")));
    ui->dateTimeEdit_2->setDateTime(QDateTime::currentDateTime());                                          //初始化为当前系统的时间

    //限制输入我们输入日期的范围只能是从2019-02-26至当前系统时间
    //TODO:这里的第一个日期能设置的时间范围最大应该只能到第二个时间当天，但这样需要在每次设置第二次时间的时候触发slot，修改第一个时间的范围，后续可以添加上以功能
    ui->dateTimeEdit->setDateRange(QDate::fromString("26MM02car2019", "d'MM'MMcaryyyy"), QDate::currentDate());
    ui->dateTimeEdit_2->setDateRange(QDate::fromString("26MM02car2019", "d'MM'MMcaryyyy"), QDate::currentDate());
}

/**
 * @brief SubWidget2::tableInit 初始化第一页的表格格式
 * @param row 表格行数
 * @param col
 */
void SubWidget2::tableInit(int row, int col)
{
    ui->tableWidget->setRowCount(row);       //设置行数
    ui->tableWidget->setColumnCount(col);    //设置列数
    ui->tableWidget->
            setHorizontalHeaderLabels
            (
                QStringList()<<"日期"<<"炉温"<<"风温1"<<"风温2"<<"风温3"<<"塔温1"<<"塔温2"<<"塔温3"<<"炉排"<<"排粮量"<<"干粮水分%"<<"原粮水分"
            );
    //ui->tableWidget->setVerticalHeaderLabels(QStringList()<<"111");
}

/**
 * @brief SubWidget2::search_by_query 通过mysql查询，将查询结果展示在表格中，同时也存入容器中
 * @param query 传入的查询语句
 */
void SubWidget2::search_by_query(QSqlQuery &query)
{
    ui->tableWidget->clearContents();   //每次查询前，先清空上次查询的内容
    this->clear_vector();               //查询前，清除一下容器中的元素

    int temp_row = query.size();               //得到表格的行数
    if(temp_row<1)
    {
        qDebug()<<"search_by_query报错:说明查询语句错了，或者说这个query查询出来就是没内容？";
        return ;
    }
    else if (temp_row>500)          //当查询出数据的个数大于500时，我们将数据集置为500
    {
        temp_row = 500;
    }
    m_row = temp_row;
    this->tableInit(m_row);             //更新一下表格的行数

    int temp=0;                 //记录当前数据是第几行
    while (query.next())        //void search_by_query(const QSqlQuery& query); //这里不能将query以常成员的形式传入，因为常成员函数不能调用普通的成员函数，即query无法调用.next()函数
    {
        for(int j=0; j < this->m_col; j++)
        {
            ui->tableWidget->setItem(temp, j, new QTableWidgetItem(query.value(j).toString()));

            if(j == 0)   //第一列数据是日期这样的，所以我们就不传入int了
            {
                //帮助向容器中插入数据
                //this->push_to_vector<QString>(j, query.value(j).toString());
                             //这样做不合适，但当下先这样试着
                m_v_date.push_back(static_cast<double>(query.value(j).toDateTime().toTime_t()));
            }
            else
            {
                this->push_to_vector(j, query.value(j).toDouble());
            }
        }
        temp++;
    }
}

/**
 * @brief SubWidget2::moveDataBase_to_table 查询所有数据，并调用search_by_query来传入表中
 */
void SubWidget2::moveDataBase_to_table()
{
    QSqlQuery query;
    query.exec(QString("select `data`, t_furnace, t_wind1, t_wind2,t_wind3, t_tower1, t_tower2, t_tower3, v_coal,v_grain, rh_after_grain, rh_before_grain FROM managesystem1_copy_copy order by data;"));

    this->search_by_query(query);
}

/**
 * @brief SubWidget2::query_by_datatime 获取按钮上的时间，产生sql语句，来搜索一段时间内的数据,返回值为获取的时间
 */
QStringList SubWidget2::query_by_datatime()
{
    QString day1, mouth1, year1, all1;
    QString day2, mouth2, year2, all2;
    //检索的起始时间
    day1 = ui->dateTimeEdit->date().toString("dd");
    mouth1 = ui->dateTimeEdit->date().toString("MM");
    year1 = ui->dateTimeEdit->date().toString("yy");
    all1 = year1+mouth1+day1;       //通过对all1与all2比较大小，来判断前一个的日期是否小于后一个的日期
    //检索的截止时间
    day2 = ui->dateTimeEdit_2->date().toString("dd");
    mouth2 = ui->dateTimeEdit_2->date().toString("MM");
    year2 = ui->dateTimeEdit_2->date().toString("yy");
    all2 = year2+mouth2+day2;

    if(all1<all2)
    {
        qDebug() << all1<<"  "<<all2<<"正确\n";
    }
    else
    {
        qDebug()<<"错误\n";
    }
    //判断输入时间是否有误
    if(not(all1<all2))              //通过对all1与all2比较大小，来判断前一个的日期是否小于后一个的日期
    {
        qDebug()<<"查询日期不能从大日期到小日期，请输入正确的日期范围";
        QMessageBox::critical(this, "输入日期有误", "输入的日期范围不能从大到小", QMessageBox::Ok);    //报出一个警告
//        return ;
    }
    else
    {
        qDebug()<<"暂时先把他查询的功能封存，全部走子线程,但是SubWidget1页调用了2的这个查询函数";
        QSqlQuery query;
        query.exec(QString("select `data`, t_furnace, t_wind1, t_wind2,t_wind3, t_tower1, t_tower2, t_tower3, v_coal,v_grain, rh_after_grain, rh_before_grain from managesystem1_copy_copy where `data` BETWEEN '%1-%2-%3' and '%4-%5-%6'").arg(year1).arg(mouth1).arg(day1).arg(year2).arg(mouth2).arg(day2));
        this->search_by_query(query);
        QStringList data = (QStringList() <<year1<<mouth1<<day1<<year2<<mouth2<<day2);
        return data;
    }
}

/**
 * @brief SubWidget2::plot_all_chart 调用后，在表中绘制所有容器的折线图
 */
void SubWidget2::plot_all_chart()
{
    //ui->chart1->clearGraphs();
    int plottableCount = ui->chart1->plottableCount();
    if(plottableCount)
    {
        qDebug()<<"1111111111111";
        //ui->chart1->clearGraphs();
        ui->chart1->clearPlottables();          //貌似不用上面那一句，只用这一句就能实现已绘图像的删除
        //ui->chart1->plotLayout()->clear();            //添加这句会报错，显示程序 异常
    }

    //打印容器内容看看
    this->print_vector_for_test<double>(m_v_t_furnace, 5);

    QPen pen;               //创建画笔
    pen.setWidth(1);        //设置笔的粗细
//    QStringList lineNames;        //原本是需要这句的，但我把lineNames弄成了成员函数，让其他人也可以用
//    lineNames <<"炉温"<< "风温1"<< "风温2"<<"风温3"<< "塔温1"<< "塔温2"<< "塔温3"<< "炉排"<<"排粮量"<< "干粮水分"<< "湿粮水分";

    //添加数据
    QVector<double> x;
    for(double i=0; i<m_v_v_coal.size(); i++)
    {
        x.push_back(i);                         //得到横坐标
    }
    for(int i=1; i<12; i++)
    {
        //向绘图区域QCustomPlot(从widget提升来的)添加一条曲线
        ui->chart1->addGraph();
        pen.setColor(QColor(qSin(i*1+1.2)*80+80, qSin(i*0.3+0)*80+80, qSin(i*0.3+1.5)*80+80));
        ui->chart1->graph()->setPen(pen);                       // 设置画笔
        ui->chart1->graph()->setName(m_lineNames.at(i-1));        //图例名称
        //ui->chart1->graph()->setData(x, this->getSequence(i));
        ui->chart1->graph()->setData(m_v_date, this->getSequence(i));           //这里传入的必须是double的数组x[i]才行，单单vector.size不行
        ui->chart1->legend->setVisible(true);       // 显示图例
    }
    //ui->chart1->graph(2)->setName(" 你好啊啊啊");
    //设置坐标轴标签名称
    ui->chart1->xAxis->setLabel("时间");
    ui->chart1->yAxis->setLabel("温度");
    ui->chart1->yAxis2->setLabel("转速");
    ui->chart1->yAxis2->setVisible(true);                       //使y2轴可见
    connect(ui->chart1->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->chart1->yAxis2, SLOT(setRange(QCPRange)));
    //设置坐标轴显示范围,否则我们只能看到默认的范围
    ui->chart1->xAxis->setRange(0, m_v_v_coal.size());
    ui->chart1->yAxis->setRange(0, 700);

    //这里是设置日期的显示格式
    QSharedPointer<QCPAxisTickerDateTime> xTicker(new QCPAxisTickerDateTime);
    xTicker->setTickCount(10);                                          //设置横坐标的个数
    xTicker->setDateTimeFormat("yyyy.MM.dd hh:mm");//
    ui->chart1->xAxis->setTicker(xTicker);
    ui->chart1->xAxis->setTickLabelRotation(30);   //设置刻度标签顺时针旋转30度   这个不需要在每个地方都设置一遍，只要有一个图表设置了，其他的都会有，但防止用户先显示另一个表，导致这个格式未设置上，所以在这里都设置了一下

    //ui->chart1->setBackground(QColor(0, 0, 0));
    ui->chart1->xAxis->setBasePen(QPen(Qt::blue, 2));
    ui->chart1->xAxis2->setBasePen(QPen(Qt::blue, 2));
    ui->chart1->yAxis->setBasePen(QPen(Qt::blue, 2));
    ui->chart1->yAxis2->setBasePen(QPen(Qt::blue, 2));
    ui->chart1->xAxis->setTickPen(QPen(Qt::blue));

    ui->chart1->rescaleAxes(true);              // 坐标轴范围自适应
    ui->chart1->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom |QCP::iSelectPlottables);     //支持鼠标拖拽，鼠标滑轮缩放，右键点选图层
    ui->chart1->replot();                       //及时将缓存区最新的图像更新到到电脑显示器上
}

/**
 * @brief SubWidget2::plot_chart 根据传入数据来绘制内容
 * @param v 储存了要画图的容器的索引
 */
void SubWidget2::plot_chart(const QVector<int> &v)          //传入的v是一个存储要画图的容器的索引
{
    int plottableCount = ui->chart1->plottableCount();  //先将之前画面清除
    if(plottableCount)
    {
        qDebug()<<"1111111111111";
        //ui->chart1->clearGraphs();
        ui->chart1->clearPlottables();          //貌似不用上面那一句，只用这一句就能实现已绘图像的删除
        //ui->chart1->plotLayout()->clear();            //添加这句会报错，显示程序 异常
    }
    QPen pen;               //创建画笔
    //pen.setWidth(4);        //设置笔的粗细
    //添加数据
    QVector<double> x;
    for(QVector<int>::const_iterator it= v.begin(); it!=v.end(); it++)
    {
        QVector<double> v_temp = this->getSequence(*it);    //根据索引，获得当前为哪一个容器
        for(double i=0; i<v_temp.size(); i++)
        {
            x.push_back(i);                         //生成横坐标的数据集
        }
        ui->chart1->addGraph();
        pen.setColor(QColor(qSin((*it)*1+1.2)*80+80, qSin((*it)*0.3+0)*80+80, qSin((*it)*0.3+1.5)*80+80));
        ui->chart1->graph()->setPen(pen);                       // 设置画笔
        ui->chart1->graph()->setName(m_lineNames.at((*it)-1));        //图例名称
        ui->chart1->graph()->setData(m_v_date, this->getSequence((*it)));           //这里传入的必须是double的数组x[i]才行，单单vector.size不行
        ui->chart1->legend->setVisible(true);       // 显示图例
    }

    ui->chart1->xAxis->setTickLabelRotation(30);//设置刻度标签顺时针旋转30度
    ui->chart1->rescaleAxes(true);              // 坐标轴范围自适应
    ui->chart1->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom |QCP::iSelectPlottables);     //支持鼠标拖拽，鼠标滑轮缩放，右键点选图层
    ui->chart1->replot();                       //及时将缓存区最新的图像更新到到电脑显示器上
}

/**
 * @brief SubWidget2::push_to_vector 向目标容器添加数据
 * @param d 目标容器的索引
 * @param data 待添加的数据
 */
//template<class T1>
void SubWidget2::push_to_vector(int d, double data)
{
    switch (d)
    {
//        case e_data:
//            if(std::is_same<T1, QString>::value)
//            {
//                m_v_date.push_back(data);
//                break;
//            }

        case e_t_furnace:
            m_v_t_furnace.push_back(data);
            break;
        case e_t_wind1:
            m_v_t_wind1.push_back(data);
            break;
        case e_t_wind2:
            m_v_t_wind2.push_back(data);
            break;
        case e_t_wind3:
            m_v_t_wind3.push_back(data);
            break;
        case e_t_tower1:
            m_v_t_tower1.push_back(data);
            break;
        case e_t_tower2:
            m_v_t_tower2.push_back(data);
            break;
        case e_t_tower3:
            m_v_t_tower3.push_back(data);
            break;
        case e_v_coal:
            m_v_v_coal.push_back(data);
            break;
        case e_v_grain:
            m_v_v_grain.push_back(data);
            break;
        case e_rh_after_grain:
            m_v_rh_after_grain.push_back(data);
            break;
        case e_rh_before_grain:
            m_v_rh_before_grain.push_back(data);
            break;
        default:
            qDebug()<<"d="<< d <<"向容器插入数据失败\n";
        break;
    }
}

/**
 * @brief SubWidget2::clear_vector 清空容器
 */
void SubWidget2::clear_vector()
{
    qDebug()<<m_v_t_wind1.size();
    m_v_date.clear();
    m_v_t_furnace.clear();
    m_v_t_wind1.clear();
    m_v_t_wind2.clear();
    m_v_t_wind3.clear();
    m_v_t_tower1.clear();
    m_v_t_tower2.clear();
    m_v_t_tower3.clear();
    m_v_v_coal.clear();
    m_v_v_grain.clear();
    m_v_rh_after_grain.clear();
    m_v_rh_before_grain.clear();
    qDebug()<<m_v_t_wind1.size();
    //将大小都重置为0
    m_v_date.resize(0);
    m_v_t_furnace.resize(0);
    m_v_t_wind1.resize(0);
    m_v_t_wind2.resize(0);
    m_v_t_wind3.resize(0);
    m_v_t_tower1.resize(0);
    m_v_t_tower2.resize(0);
    m_v_t_tower3.resize(0);
    m_v_v_coal.resize(0);
    m_v_v_grain.resize(0);
    m_v_rh_after_grain.resize(0);
    m_v_rh_before_grain.resize(0);
    qDebug()<<m_v_t_wind1.size();
}

/**
 * @brief SubWidget2::getSequence 根据索引得到目标容器
 * @param i 容器索引
 * @return
 */
QVector<double>& SubWidget2::getSequence(int i)
{
    switch (i)
    {
        case e_data:
            return m_v_date;
        case e_t_furnace:
            return m_v_t_furnace;
            break;
        case e_t_wind1:
            return m_v_t_wind1;
            break;
        case e_t_wind2:
            return m_v_t_wind2;
            break;
        case e_t_wind3:
            return m_v_t_wind3;
            break;
        case e_t_tower1:
            return m_v_t_tower1;
            break;
        case e_t_tower2:
            return m_v_t_tower2;
            break;
        case e_t_tower3:
            return m_v_t_tower3;
            break;
        case e_v_coal:
            return m_v_v_coal;
            break;
        case e_v_grain:
            return m_v_v_grain;
            break;
        case e_rh_after_grain:
            return m_v_rh_after_grain;
            break;
        case e_rh_before_grain:
            return m_v_rh_before_grain;
            break;
        default:
            qDebug()<<"获取容器失败了";
        break;
    }
    qDebug()<<"getSequence(int i) ：未找到您想要获取的容器，请重新输入"<<endl;
}

template <class T>
void SubWidget2::print_vector_for_test(const QVector<T>& vector1, int max)
{
    if(!max)         //如果不填入max值，则给其赋予默认值0，从而调用这个if语句，将max变为容器最大值
    {
        max=vector1.size();
    }
    int i=0;
    for(typename QVector<T>::const_iterator it=vector1.begin(); it!=vector1.end(); it++)  //这里要添加一个typename,我感觉应该是起别名啥的
    {
        qDebug()<<*it<<"   ";
        if(i++>=max){break;}
    }
    qDebug()<<endl;
}

/**
 * @brief SubWidget2::closeEvent 重写关闭窗口事件
 * @param event 我们不想让窗口被这个子窗口关闭，所以忽略这个子窗口触发的关闭事件
 */
void SubWidget2::closeEvent(QCloseEvent *event)
{
    qDebug()<<"尝试关闭窗口2";
    this->close();
    //event->accept();    //接收关闭事件
    //event->ignore();    //忽略关闭窗口的事件，因为 我们不想让创建的对象关闭
}

/**
 * @brief updata_vector 这个函数是用来，通过外界的容器更新SubWidget2内部私有容器用的
 * @index 目标容器的索引
 * @vector1 外界传入的容器
 */
//template <class T>
//void SubWidget2::updata_vector(int index, T vector1)
void SubWidget2::updata_vector(int index, const QVector<double>& vector1)
{
    //清空容器
    getSequence(index).clear();
    getSequence(index).resize(0);
    //将传入容器内容通过copy assignment函数赋值给目标容器
    getSequence(index) = vector1;
    qDebug()<<"1111111111   "<<getSequence(index).size();
}

SubWidget2::~SubWidget2()
{
    delete ui;
}
